-
Notifications
You must be signed in to change notification settings - Fork 274
feat(breaking): migrate Flow to TS; remove some deprecated functions and aliases #881
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
<TouchableOpacity | ||
accessibilityHint={BUTTON_HINT} | ||
accessibilityLabel={BUTTON_LABEL} | ||
accessibilityRole="button" | ||
// @ts-ignore - accessibilityStates removed in RN 0.62 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we consider dropping support for that? Just curious
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe try accessibilityState={{ selected: true }}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We do support accessibilityState
(see below for instance, my question is that since RN 0.62 doesn't support accessibilityStates
anymore, should we support it? And if yes, for how long?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the oldest React-Native version mentioned in docs is >= 0.61
and I see no clear "minimum supported React Native version" info, I'd assume people can be using RNTL in 0.61~ versions where accessibilityStates
prop is still around. Thus I'd keep it if it does not incur big maintenance cost.
expect( | ||
disabledSelected && disabledSelected.props.accessibilityStates | ||
).toEqual(['selected', 'disabled']); | ||
expect(disabledSelected?.props.accessibilityStates).toEqual([ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It runs TS linter rules now, is it something we want? Perhaps we need to make sure that this doesn't have more impact (some JS rules disappearing, or something like that?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since it extends callstack
ESLint preset I think it's more of a concern of @callstack/eslint-config
to maintain parity between the two? I've quickly checked and I don't see glaring differences between JS/TS configs. @thymikee do you think it may be a problem?
/** | ||
* Wait for microtasks queue to flush | ||
*/ | ||
export default function flushMicrotasksQueue<T>(): Thenable<T> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Deleted this one
src/helpers/a11yAPI.ts
Outdated
findByLabelText: (string | RegExp, ?WaitForOptions) => FindReturn, | ||
findAllByA11yLabel: (string | RegExp, ?WaitForOptions) => FindAllReturn, | ||
findAllByLabelText: (string | RegExp, ?WaitForOptions) => FindAllReturn, | ||
getByA11yLabel: (label: string | RegExp) => GetReturn; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we consider deprecating the aliases?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess I would keep them for the time being, as not all a11y queries have their RTL-like counterpart.
@thymikee wdyt?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my ideal world each query should exists only once (no alias) and have the same behaviour as on web. For instance, we could drop getByA11yLabel
and keep getByLabelText
, since this one is supported on both platforms.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's get rid of aliases for queries that are available on RTL, like ByLabelText for example. It's a simple search-replace change, so no biggie
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed the *LabelText
and *Role
aliases.
@@ -0,0 +1,17 @@ | |||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copied from the repack
one, adding jsx support
c5bdbec
to
f863bf1
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work @AugustinLF! I strongly support moving from Flow to Typescript as a better and de-facto standard type-checking solution.
src/helpers/errors.ts
Outdated
} | ||
throw new ErrorWithStack(error.message, callsite); | ||
|
||
throw new ErrorWithStack('Something wrong happened when querying', callsite); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider something along the lines:
throw new ErrorWithStack('Something wrong happened when querying', callsite); | |
throw new ErrorWithStack(`Query: caught unknown error type: ${typeof error}, value: ${error?.toString()}`, callsite); |
src/helpers/byDisplayValue.ts
Outdated
@@ -23,7 +23,10 @@ const getTextInputNodeByDisplayValue = ( | |||
matches(value, nodeValue, normalizer, exact) | |||
); | |||
} catch (error) { | |||
throw createLibraryNotSupportedError(error); | |||
if (error instanceof Error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should not silently ignore the non-Error
values. It should be better to just analyse the error
type inside the createLibraryNotSupportedError
.
src/helpers/a11yAPI.ts
Outdated
findByLabelText: (string | RegExp, ?WaitForOptions) => FindReturn, | ||
findAllByA11yLabel: (string | RegExp, ?WaitForOptions) => FindAllReturn, | ||
findAllByLabelText: (string | RegExp, ?WaitForOptions) => FindAllReturn, | ||
getByA11yLabel: (label: string | RegExp) => GetReturn; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess I would keep them for the time being, as not all a11y queries have their RTL-like counterpart.
@thymikee wdyt?
typings/test_index.js
Outdated
@@ -11,15 +10,15 @@ import { | |||
within, | |||
getQueriesForElement, | |||
getDefaultNormalizer, | |||
} from '../..'; | |||
} from '@testing-library/react-native'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@thymikee you suggested to export flow types the same way we did with TS, but I can't get the import here to work (hence the red build), are you familiar with how to do that?
f99fddb
to
fa9a1c5
Compare
@thymikee I just rebased to fix the conflict, and I believe I addressed all the comments (only left one is mine #881 (comment) waiting for your input). Is there anything else you'd like me to do? |
@AugustinLF I see that Flow check is failing, would be cool to remove it :) Other than that please just wait a bit more for me to find time and review this. Thanks so much for the work you've done already! |
Yeah, the issue with the flow check is that I don't know how to make it possible to "test" the flow types #881 (comment). If I remove the test file for the types the build pass, but then we have no guarantee that the flow types are correct. Thanks for taking the time reviewing :) |
expect(getAllByA11yLabel).toBe(getAllByLabelText); | ||
expect(queryAllByA11yLabel).toBe(queryAllByLabelText); | ||
expect(findAllByA11yLabel).toBe(findAllByLabelText); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While we may discuss about usefulness of this test, why it gets removed with this PR? :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test just checks that aliases work and we removed them
src/__tests__/act.test.tsx
Outdated
import * as React from 'react'; | ||
import { Text } from 'react-native'; | ||
import ReactTestRenderer from 'react-test-renderer'; | ||
import act from '../act'; | ||
import render from '../render'; | ||
import fireEvent from '../fireEvent'; | ||
|
||
const UseEffect = ({ callback }: { callback: Function }) => { | ||
type UseEffectProps = { callback: () => void }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
small improvement (?):
type UseEffectProps = { callback: () => void }; | |
type UseEffectProps = { callback(): void }; |
@@ -11,7 +10,7 @@ beforeAll(() => { | |||
|
|||
let isMounted = false; | |||
|
|||
class Test extends React.Component<*> { | |||
class Test extends React.Component<any> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
class Test extends React.Component<any> { | |
class Test extends React.Component { |
src/__tests__/auto-cleanup.test.tsx
Outdated
import * as React from 'react'; | ||
import { View } from 'react-native'; | ||
import { render } from '..'; | ||
|
||
let isMounted = false; | ||
|
||
class Test extends React.Component<*> { | ||
class Test extends React.Component<{ onUnmount?: () => void }> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here you can also do the same treatment onUnmount?(): void
or keep it as-is. Decision is yours, I find the latter a little bit easier to read.
src/__tests__/byText.test.tsx
Outdated
@@ -146,7 +148,8 @@ describe('findBy options deprecations', () => { | |||
}); | |||
|
|||
test.skip('getByText works properly with custom text component', () => { | |||
function BoldText({ children }) { | |||
type BoldTextProps = { children: React.ReactNode }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about extracting this to higher scope:
type ChildrenProps = { children: React.ReactNode }
And then reuse for all tests expecting children
?
export function flushMicroTasks<T>(): Thenable<T> { | ||
return { | ||
// using "thenable" instead of a Promise, because otherwise it breaks when | ||
// using "modern" fake timers |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you check if it's still the case with TypeScript bindings for jest
(@types/jest
)? Keeping this type may be not optimal if it's not needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not a type issue (btw @types/jest
are already installed), that comment/code was already there.
Looks mostly good to me. I'd definitely take a look whether we can get rid of Thenable in https://github.com/callstack/react-native-testing-library/pull/881/files#r792187961 flushMicroTasks after migration from Flow to TypeScript.
Sounds like a good plan to me.
src/helpers/byDisplayValue.ts
Outdated
value, | ||
options?: TextMatchOptions = {} | ||
node: ReactTestInstance, | ||
value: string | RegExp, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this particular union may deserve an alias because of its widespread use. WDYT @thymikee?
src/helpers/byText.ts
Outdated
const getChildrenAsText = (children, TextComponent) => { | ||
const textContent = []; | ||
const getChildrenAsText = ( | ||
children: (string | number | React.ReactElement)[], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
children: (string | number | React.ReactElement)[], | |
children: React.ReactChild[], |
src/helpers/timers.ts
Outdated
@@ -30,20 +28,21 @@ function getJestFakeTimersType() { | |||
} | |||
|
|||
if ( | |||
// @ts-ignore jest mutates setTimeout |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's a good place to use @ts-expect-error
instead of @ts-ignore
. We know that there'll be TS error here so no error is an undesired behavior as well.
src/waitFor.ts
Outdated
await act(async () => { | ||
result = await waitForInternal(expectation, optionsWithStackTrace); | ||
}); | ||
|
||
//$FlowFixMe: either we have result or `waitFor` threw error | ||
// @ts-ignore either we have result or `waitFor` threw error | ||
return result; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can use !
operator to force TS to trust you it's always valid. You can keep the comment though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks mostly good to me. I'd definitely take a look whether we can get rid of Thenable
in https://github.com/callstack/react-native-testing-library/pull/881/files#r792187961 flushMicroTasks
after migration from Flow to TypeScript.
Also string | RegExp
type may be aliased to something more in testing-library
nomenclature. The rest of my comments are small stylistic improvements & small type improvements (like using React.ReactChild
instead of enumerating possibilities, or restricting any
in some places).
8d9e4f3
to
c5b2a22
Compare
@Killavus I should have addressed all your comments (or answered). I just let one hanging, waiting for a confirmation. Please let me know if you need anything else! |
@Killavus can I be of any help, or do anything to help getting that merged? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good and ready to be merged. However, since this is a breaking change, I wonder if we shouldn't tackle #934 first and release it in a minor release. WDYT?
Sounds fair to me! |
@AugustinLF v9.1.0 is released so let's rebase this and we can merge this work 🚀 |
a6a19fa
to
3f53f1e
Compare
@thymikee rebased. However CI didn't not thing to have been triggered, did you change anything recently? |
@AugustinLF nothing else than merging a bunch of Dependabot PRs |
There's some outage around self-hosted runners, may be related: https://status.circleci.com |
Thank you @AugustinLF! |
This is the first draft of a PR to switch from flow to TS. The PR includes a green build for typescript and tests. It also includes the deletion of several deprecated APIs as discussed in #877.
There is still a bit left to do, but I'd like to have to have a 👍 before fixing those:
Removed functionality:
waitForElement
shallow
flushMicrotasksQueue
Closes #877